package com.eralink.uhfreaderlib;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

class NetworkReader implements Reader {
    private final String remoteIp;
    private final int remotePort;
    private Socket socket;

    NetworkReader(final String remoteIp, final int remotePort) {
        this.remoteIp = remoteIp;
        this.remotePort = remotePort;
    }

    @Override
    public int open() {
        if (socket != null) {
            return EraLinkUHFReaderApiError.ErrAlreadyOpened;
        }

        SocketAddress address;
        try {
            address = new InetSocketAddress(remoteIp, remotePort);
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
            return EraLinkUHFReaderApiError.ErrCommunicationError;
        } catch (SecurityException e) {
            e.printStackTrace();
            return EraLinkUHFReaderApiError.ErrOpenFailed;
        } catch (Exception e) {
            e.printStackTrace();
            return EraLinkUHFReaderApiError.ErrOpenFailed;
        }

        int ret;
        socket = new Socket();
//        try {
//            socket.setSoTimeout(20);
//        } catch (SocketException e) {
//            e.printStackTrace();
//        }

        Callable<Integer> callable = () -> {
            int ret1 = EraLinkUHFReaderApiError.ErrNoError;
            try {
                socket.connect(address, 3000);
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
                ret1 = EraLinkUHFReaderApiError.ErrCommunicationError;
            } catch (SocketTimeoutException e) {
                e.printStackTrace();
                ret1 = EraLinkUHFReaderApiError.ErrTimeout;
            } catch (IOException e) {
                e.printStackTrace();
                ret1 = EraLinkUHFReaderApiError.ErrCommunicationError;
            } catch (Exception e) {
                e.printStackTrace();
                ret1 = EraLinkUHFReaderApiError.ErrCommunicationError;
            }

            return ret1;
        };

        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        Thread connectThread = new Thread(futureTask);
        connectThread.start();
        try {
            ret = futureTask.get();
        } catch (ExecutionException e) {
            e.printStackTrace();
            ret = EraLinkUHFReaderApiError.ErrCommunicationError;
        } catch (InterruptedException e) {
            e.printStackTrace();
            ret = EraLinkUHFReaderApiError.ErrCommunicationError;
        }

        if (ret != EraLinkUHFReaderApiError.ErrNoError) {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            socket = null;
        }

        return ret;
    }

    @Override
    public int close() {
        if (socket != null) {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            socket = null;
        }
        return EraLinkUHFReaderApiError.ErrNoError;
    }

    public int read(final byte[] buffer, final int[] offset, final int size) {
        if (null == socket) {
            return EraLinkUHFReaderApiError.ErrNoError;
        }

        try {
            InputStream inputStream = socket.getInputStream();
            final int readSize = inputStream.read(buffer, offset[0], size);
            if (0 < readSize) {
                offset[0] += readSize;
            }
            if (-1 == readSize) {
                return EraLinkUHFReaderApiError.ErrCommunicationError;
            }
        } catch (IOException e) {
            e.printStackTrace();
            return EraLinkUHFReaderApiError.ErrCommunicationError;
        }
        return EraLinkUHFReaderApiError.ErrNoError;
    }

    public int write(final byte[] buffer, final int offset, final int len) {
        if (null == socket) {
            return EraLinkUHFReaderApiError.ErrNotOpened;
        }

        Callable<Integer> callable = () -> {
            try {
                OutputStream outputStream = socket.getOutputStream();
                outputStream.write(buffer, offset, len);
                outputStream.flush();
            } catch (IOException e) {
                e.printStackTrace();
                return EraLinkUHFReaderApiError.ErrCommunicationError;
            }
            return EraLinkUHFReaderApiError.ErrNoError;
        };
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        Thread sendThread = new Thread(futureTask);
        sendThread.start();

        int ret = EraLinkUHFReaderApiError.ErrNoError;
        try {
            ret = futureTask.get();
        } catch (ExecutionException | InterruptedException e) {
            e.printStackTrace();
            ret = EraLinkUHFReaderApiError.ErrRequestFailed;
        }

        return ret;
    }
}
